/* eslint-disable @typescript-eslint/explicit-function-return-type */
import {
  ref,
  defineComponent,
  Ref,
  watch,
  computed,
  onBeforeUnmount,
} from 'vue';
import {
  getSpanProps,
  useFocusAndBlur,
  useNamespace,
} from '@ibiz-template/vue3-util';
import { isNil } from 'ramda';
import { DataTypes } from '@ibiz-template/core';
import dayjs from 'dayjs';
import customParseFormat from 'dayjs/plugin/customParseFormat';
import { OdooPersonalInfoEditorController } from './editor.controller';
import './odoo-personal-info.scss';

dayjs.extend(customParseFormat);

function isValidDateFormat(dateStr: string, format: string): boolean {
  if (dateStr === format) {
    return false;
  }
  return dayjs(dateStr, format, true).isValid(); // 严格模式判断是否是复合值格式化要求的日期文本
}

export const OdooPersonalInfo = defineComponent({
  name: 'IBizOdooPersonalInfo',
  props: getSpanProps<OdooPersonalInfoEditorController>(),
  setup(props, { emit }) {
    const ns = useNamespace('personal-info');
    const ns2 = useNamespace('odoo-personal-info');

    const c = props.controller;

    const text: Ref<string> = ref('');

    // 加载失败图片集合
    const loadErrorMap: Ref<string[]> = ref([]);

    // 文本分隔符
    const textSeparator =
      c.model.textSeparator || c.editorParams?.TEXTSEPARATOR || ',';

    // 聚焦失焦事件
    const { componentRef: editorRef } = useFocusAndBlur(
      () => emit('focus'),
      () => emit('blur'),
    );

    // 是否显示表单默认内容
    const showFormDefaultContent = computed(() => {
      if (props.controlParams && props.controlParams.editmode === 'hover') {
        return true;
      }
      return false;
    });

    // 增加状态存储URL验证结果
    const avatarCache = ref<Record<string, string>>({});
    // 记录正在请求中的 fileId
    const loadingCache = new Set<string>();

    /**
     * 效验下载文件凭证，全局参数enableDownloadTicket为true时开启验证逻辑
     *
     * @param {string} fileId
     * @return {*}
     */
    const verifyFileTicket = async (fileId: string): Promise<void> => {
      if (avatarCache.value[fileId] || loadingCache.has(fileId)) return;

      loadingCache.add(fileId);
      try {
        const { downloadUrl } = ibiz.util.file.calcFileUpDownUrl(
          c.context,
          c.params,
          props.data,
          c.editorParams,
        );

        let finalUrl = '';
        if (ibiz.config.common.enableDownloadTicket) {
          const downloadTicket = await ibiz.util.file.getDownloadTicket(
            c.context,
            c.params,
            props.data,
            {
              fileId,
            },
            {
              dataFieldTag: 'srfkey',
            },
          );
          if (downloadTicket?.ticket) {
            finalUrl = downloadUrl.replace('%fileId%', downloadTicket.ticket);
          }
        } else {
          finalUrl = downloadUrl.replace('%fileId%', fileId);
        }

        if (finalUrl) {
          avatarCache.value[fileId] = finalUrl;
        }
      } catch (err) {
        ibiz.log.warn(err);
      } finally {
        loadingCache.delete(fileId);
      }
    };

    watch(
      () => props.value,
      (newVal, oldVal) => {
        if (newVal !== oldVal) {
          if (isNil(newVal)) {
            text.value = '';
            return;
          }
          let tempVal = '';
          const { valueFormat, dataType, unitName } = c.parent;
          if (c.model.valueType === 'SIMPLES') {
            tempVal = (newVal as string[]).join(textSeparator);
          } else if (c.model.valueType === 'OBJECT') {
            tempVal = (newVal as IData)[
              c.model.objectNameField ? c.model.objectNameField : 'srfmajortext'
            ];
          } else if (c.model.valueType === 'OBJECTS') {
            const tempValue: string[] = [];
            (newVal as IData[]).forEach((_item: IData) => {
              tempValue.push(
                _item[
                  c.model.objectNameField
                    ? c.model.objectNameField
                    : 'srfmajortext'
                ],
              );
            });
            tempVal = tempValue.join(textSeparator);
          } else if (c.model.editorType === 'ADDRESSPICKUP') {
            // 解析地址选择器的JSON字符串数据
            try {
              const tempValue: string[] = [];
              const tempItems: IData[] = JSON.parse(newVal as string);
              tempItems.forEach((_item: IData) => {
                tempValue.push(
                  _item[
                    c.model.objectNameField
                      ? c.model.objectNameField
                      : 'srfmajortext'
                  ],
                );
              });
              tempVal = tempValue.join(textSeparator);
            } catch (error) {
              ibiz.log.error(`标签地址选择器的值不符合JSON格式${newVal}`);
            }
          } else if (valueFormat) {
            try {
              if (dataType != null && DataTypes.isDate(dataType)) {
                tempVal = dayjs(newVal as string).format(valueFormat);
              } else {
                // 面板属性项是拿不到dataType的，此时先用dayjs格式化，如果能格出来说明是时间型，否则走text-format
                const tempValue = dayjs(newVal as string).format(valueFormat);
                if (isValidDateFormat(tempVal, valueFormat)) {
                  tempVal = tempValue;
                } else {
                  tempVal = ibiz.util.text.format(`${newVal}`, valueFormat);
                }
              }
            } catch (error) {
              tempVal = `${newVal}`;
              ibiz.log.error(`${newVal} 值格式化错误`);
            }
          } else {
            tempVal = `${newVal}`;
          }
          if (unitName) {
            tempVal += unitName;
          }
          text.value = tempVal;
        }
      },
      {
        immediate: true,
      },
    );

    const showText = computed(() => {
      return text.value;
    });

    const imgLoadError = (url: string) => {
      loadErrorMap.value.push(url);
    };

    onBeforeUnmount(() => {
      avatarCache.value = {};
      loadingCache.clear();
    });

    // 绘制人员头像
    const renderUserAvatar = (): JSX.Element | string => {
      let avatarUrl = '';
      const _iconurl = props.data[c.avatarField];
      if (_iconurl) {
        const icon = JSON.parse(_iconurl);
        const fileId = icon[0].id;
        avatarUrl = avatarCache.value[fileId];

        if (!avatarUrl) {
          verifyFileTicket(fileId);
        }
      }
      if (avatarUrl && loadErrorMap.value.indexOf(avatarUrl) === -1) {
        return (
          <img
            class={[
              ns.bem('content', 'head-sculpture', 'avatar-icon'),
              ns2.bem('content', 'head-sculpture', 'avatar-icon'),
            ]}
            src={avatarUrl}
            onError={() => imgLoadError(avatarUrl)}
            alt=''
          />
        );
      }
      return ibiz.util.text.abbreviation(showText.value) || '';
    };

    const renderContent = (): JSX.Element | string => {
      const tempVal = text.value;
      if (!tempVal) {
        return '- - -';
      }
      const img = c.parseAvatar(tempVal);
      if (img && loadErrorMap.value.indexOf(img) === -1) {
        return (
          <div class={[ns.b('content'), ns2.b('content')]}>
            <div
              class={[
                ns.be('content', 'head-sculpture'),
                ns2.be('content', 'head-sculpture'),
              ]}
            >
              <img src={img} onError={() => imgLoadError(img)}></img>
            </div>
          </div>
        );
      }
      return (
        <div class={[ns.b('content'), ns2.b('content')]}>
          <div
            class={[
              ns.be('content', 'head-sculpture'),
              ns2.be('content', 'head-sculpture'),
            ]}
            style={`background-color:${ibiz.util.text.stringToHexColor(
              showText.value,
            )}`}
          >
            {renderUserAvatar()}
          </div>
          {c.isShowNameText() ? (
            <div class={[ns.be('content', 'tip'), ns2.be('content', 'tip')]}>
              {showText.value}
            </div>
          ) : null}
        </div>
      );
    };

    return {
      ns,
      ns2,
      c,
      text,
      editorRef,
      showFormDefaultContent,
      renderContent,
    };
  },
  render() {
    return (
      <div
        class={[
          this.ns.b(),
          this.ns2.b(),
          this.readonly ? this.ns.m('readonly') : '',
          this.readonly ? this.ns2.m('readonly') : '',
          this.ns.is('show-default', this.showFormDefaultContent),
        ]}
        ref='editorRef'
      >
        {this.renderContent()}
      </div>
    );
  },
});
